#include "sct/encode/videoenc.h"

namespace sct
{
CVideoEnc::CVideoEnc(const CodecType codecType):CEncodeInterface(codecType),
		mFrame(NULL),
		mCodec(NULL),
		mCodecCtx(NULL)
{
	bzero(&mEncodeParam, sizeof(mEncodeParam));
}
void CVideoEnc::init(const CEncodeParam & param)
{
	mEncodeParam = param;

	///find encoder
	switch(mCodecType)
	{
	case CT_H264:
	{
		mCodec = avcodec_find_encoder(CODEC_ID_H264);

		break;
	}

	default:
	{
		SCT_LOGD();
		break;
	}
	}

	if(!mCodec)
	{
		SCT_LOGD("codec:%d not found!", mCodecType);
		exit(1);
	}

	mCodecCtx = avcodec_alloc_context3(mCodec);
	mFrame = avcodec_alloc_frame();

	AVRational rate;
	rate.num = 1;

	mCodecCtx->bit_rate = mEncodeParam.bitrate;
	mCodecCtx->width = mEncodeParam.width;
	mCodecCtx->height = mEncodeParam.height;
	mCodecCtx->gop_size = mEncodeParam.gopsize;
	mCodecCtx->max_b_frames = mEncodeParam.max_b_frames;

	rate.den = mEncodeParam.fps;
	mCodecCtx->pix_fmt = PIX_FMT_YUV420P;

	///set codec relative data.
	switch(mCodecType)
	{
	case CT_H264:
	{

		if(mCodecCtx->priv_data)
		{
			av_opt_set(mCodecCtx->priv_data, "preset", "superfast", 0);
			av_opt_set(mCodecCtx->priv_data, "tune", "zerolatency", 0);
	//		av_opt_set(_pCodecCtx->priv_data, "sps-id", "7", 0);
	//		av_opt_set(_pCodecCtx->priv_data, "pps-id", "8", 0);
		}
		break;
	}

	default:
	{
		SCT_LOGD();
		break;
	}
	}

	mCodecCtx->time_base = rate;

	if(avcodec_open2(mCodecCtx, mCodec, NULL)<0)
	{
		SCT_LOGD("open codec failed");
		exit(2);
	}
}

CVideoEnc::~CVideoEnc()
{
	if(mFrame)
	{
		av_frame_free(&mFrame);
	}

	if(mCodecCtx)
	{
		avcodec_free_context(&mCodecCtx);
	}

}
void CVideoEnc::encodeOneFrame(const int64_t pts, const void* buf, const int len)
{
	int64_t t = pts;
	t = pts * mEncodeParam.fps;
	t /= 1000000;
	mFrame->pts =  t;

	const uint8_t * p = (const uint8_t*)buf;
	mFrame->data[0] = (uint8_t*)p;
	mFrame->linesize[0] = mEncodeParam.width;

	mFrame->data[2] = (uint8_t*)p + mEncodeParam.width*mEncodeParam.height;
	mFrame->linesize[2] = mEncodeParam.width/2;

	mFrame->data[1] = (uint8_t*)p + mEncodeParam.width*mEncodeParam.height * 5/4;
	mFrame->linesize[1] = mEncodeParam.width/2;

	AVPacket avpkt;
	av_init_packet(&avpkt);
	avpkt.data = NULL;
	avpkt.size = 0;

	int got_packet_ptr = 0;

	int ret = avcodec_encode_video2(mCodecCtx, &avpkt, mFrame, &got_packet_ptr);
	if(ret < 0)
	{
		SCT_LOGD("encode one frame error!");
	}

	if(1 == got_packet_ptr)
	{

		t = avpkt.pts;
		t *= 1000000;
		t /= mEncodeParam.fps;

		CBlockInfo info;
		info.pts = t;
		mCallback->onGenData(this, avpkt.data, avpkt.size, info);

		av_free_packet(&avpkt);
	}
}
}
